#ifndef _H_C_PROTOCOL_HEADER_H_
#define _H_C_PROTOCOL_HEADER_H_

#include "../typedefine.h"

namespace QWER
{
    QCLASS CProtocolStream;

	QDLL_EXPORT QENUM EProtocolHeaderType
	{
		ProtocolId = 0,
		SrcAddress = 1,
		SrcURIOrSession = 2,
		DstAddress = 3,
		DstURIOrSession = 4,
		IsRpcRet = 5,
        RpcArgUID = 6,
        SrcIpPort = 7,
        DstIpPort = 8,
		ErrorCode = 9,

		MaxReservedNum = 31,

        MaxNum = 63
	};

	QDLL_EXPORT QCLASS CProtocolHeader
	{
	public:
		inline BOOLN CloneTo(PTR_OR_REF(CProtocolHeader) roData) QCONST_FUNC
		{
			PTR(CProtocolHeader) poHandshakeData = TO_PTR2(roData);
			if (poHandshakeData == NULL_PTR)
				return false;
			poHandshakeData->m_qwMask = m_qwMask;
#ifdef _USING_CLI
			poHandshakeData->m_oDatas.Clear();
			poHandshakeData->m_oDatas.AddRange(TO_PTR(m_oDatas));
#else
			poHandshakeData->m_oDatas = m_oDatas;
#endif
			return true;
		}

		inline CUniquePtr(CProtocolHeader) Clone() QCONST_FUNC
		{
			CUniquePtr(CProtocolHeader) poData(QNEW CProtocolHeader());
			if (false == CloneTo(TO_REF2(QGetFromUniquePtr(poData))))
				return NULL_PTR;
			return QMOVE(poData);
		}

#ifdef _USING_CLI
	public:
#else
	protected:
#endif
		void Marshal(CProtocolStream& ros) QCONST_FUNC;

		void Unmarshal(CProtocolStream& ros);

	public:
		inline UINT8 Size() QCONST_FUNC
		{
			return (m_qwMask == 0 ? 0 : _Ones(m_qwMask));
		}

		bool TryGet(EProtocolHeaderType eKey, REF(UINT64) qwValue) QCONST_FUNC
        {
            return TryGet((UINT8)eKey, qwValue);
        }

		bool TryGet(UINT8 btKey, REF(UINT64) qwValue) QCONST_FUNC
		{
			UINT64 qwTest = ((UINT64)1) << btKey;
			if ((m_qwMask & qwTest) == 0)
				return false;
			qwValue = m_oDatas[btKey];
			return true;
		}

		void Set(EProtocolHeaderType eKey, UINT64 qwValue)
        {
            Set((UINT8)eKey, qwValue);
        }

		void Set(UINT8 btKey, UINT64 qwValue)
		{
			if (btKey >= m_oDatas.size())
				m_oDatas.resize(btKey + 1);
			m_oDatas[btKey] = qwValue;
			m_qwMask |= ((UINT64)1) << btKey;
		}

		void Del(EProtocolHeaderType eKey)
        {
            Del((UINT8)eKey);
        }

		void Del(UINT8 btKey)
		{
			m_qwMask &= ~(((UINT64)1) << btKey);
		}

		void Clear()
		{
			m_qwMask = 0;
			m_oDatas.clear();
		}

	private:
		inline UINT8 _Ones(UINT32 x) QCONST_FUNC
		{
			x -= ((x >> 1) & 0x55555555);
			x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
			x = (((x >> 4) + x) & 0x0f0f0f0f);
			x += (x >> 8);
			x += (x >> 16);
			return UINT8(x & 0x0000003f);
		}

		inline UINT8 _Ones(UINT64 x) QCONST_FUNC
		{
			return _Ones((UINT32)x) + _Ones((UINT32)(x >> 32));
		}

	private:
		UINT64 m_qwMask = 0;
		CVector(UINT64) m_oDatas;
#ifdef _USING_CLI
		static Array<UINT8>^ m_sTable = gcnew Array<UINT8>(
			63, 30, 3, 32, 59, 14, 11, 33,
			60, 24, 50, 9, 55, 19, 21, 34,
			61, 29, 2, 53, 51, 23, 41, 18,
			56, 28, 1, 43, 46, 27, 0, 35,
			62, 31, 58, 4, 5, 49, 54, 6,
			15, 52, 12, 40, 7, 42, 45, 16,
			25, 57, 48, 13, 10, 39, 8, 44,
			20, 47, 38, 22, 17, 37, 36, 26
		);
#else
		static UINT8 m_sTable[64];
#endif
	};
}

#endif
